home *** CD-ROM | disk | FTP | other *** search
/ Computer Shopper 235 / Issue 235 - September 2007 - DPCS0907DVD.ISO / Extras / NetObjects Fusion / NOF10.exe / data1.cab / FSI / lib / nof / dataobjects / tables / Table.js < prev    next >
Encoding:
JavaScript  |  2007-04-11  |  17.5 KB  |  541 lines

  1. /**
  2.   * FieldType constants for the database type currently supported by Fusion for internal tables
  3. */
  4.  
  5. function NOF_DataObjects_FieldType(){
  6. }
  7.  
  8. NOF_DataObjects_FieldType.prototype.VARCHAR    = 0;
  9. NOF_DataObjects_FieldType.prototype.INTEGER    = 1;
  10. NOF_DataObjects_FieldType.prototype.BYTES_LIST = 2;
  11. NOF_DataObjects_FieldType.prototype.IMAGE_PATH = 3;
  12. NOF_DataObjects_FieldType.prototype.LARGE_TEXT = 4;
  13. NOF_DataObjects_FieldType.prototype.DATE       = 5; //TODO: determine the actual value for DATETIME. it's treated as LONG
  14. NOF_DataObjects_FieldType.prototype.REAL       = 6;
  15. NOF_DataObjects_FieldType.prototype.INTERNAL_PAGE_LINK  = 7;
  16.  
  17.  
  18. /**
  19.   * FieldInfo class constructor
  20.   * @param name field name
  21.   * @param type field type as permitted by FieldType
  22.   * @param [position] to be used when the physical order fields get created matters
  23. */
  24. function NOF_DataObjects_FieldInfo(name, type, position){
  25.   this.name     = name;
  26.   this.type     = type;
  27.   this.position = position;
  28. }
  29.  
  30. /**
  31.   * FieldValue class constructor
  32.   * @param name field name
  33.   * @param value field value
  34. */
  35. function NOF_DataObjects_FieldValue( name, value){
  36.   this.name     = name;
  37.   this.value    = value;
  38. }
  39.  
  40. /**
  41.   * Table class constructor
  42.   * @param type  the table type. currently is computed as a BaseId + StoreId
  43.   * @param name  the table name
  44.   * @param [pkName] the primary key if any. these are autoincremented and cannot be set
  45. */
  46. function NOF_DataObjects_Table( type, name, pkName){
  47.   this.__proto__       = NOF_DataObjects_Table.prototype;
  48.  
  49.   if (arguments.length > 0){ //not a default contructor call
  50.     this.type   = type;
  51.     this.name   = name;
  52.     this.pkName = pkName;
  53.     this.fisSelection = null;
  54.   }
  55. }
  56.  
  57. function NOF_DataObjects_Table_ProtoBuilder(){
  58.   var NOF_DataObjects_Table_Sequences = new Array();
  59.   var NOF_DataObjects_Table_SelectionsList = new Array();
  60.   var NOF_DataObjects_Table_LoadedTables = new Array();
  61.  
  62.   var method = NOF_DataObjects_Table.prototype;
  63.  
  64.   //these are *NOT* static as long as you access them via classInstance.propertyName
  65.   method.type   = null;
  66.   method.name   = null;
  67.   method.pkName = null;
  68.   method.fisSelection = null;
  69.   method.instanceId   = -1;
  70.  
  71.   /**
  72.     * getNextSequence
  73.  
  74.     * @return the next sequence value for the primary key
  75.   */
  76.   method.getNextSequence = function getNextSequence(){
  77.     //the starting value is set in getTable();
  78.     //NOF.Contract.Assert( NOF_DataObjects_Table_Sequences[ this.getFullTableName() ] != null, "Sequence not initialized for " + this.getFullTableName());
  79.     return ++NOF_DataObjects_Table_Sequences[ this.getFullTableName() ];
  80.   };
  81.  
  82.   method._setSequence = function _setSequence( seq ){
  83.     NOF_DataObjects_Table_Sequences[ this.getFullTableName() ] = seq;
  84.   };
  85.  
  86.   /**
  87.     * insert inserts a new row
  88.     * @param fields  array of FieldInfo objects
  89.  
  90.     * @return pkValue the pkValue for inserted if the table has one or -1 otherwise
  91.   */
  92.   method.insert = function insert( fields ){
  93.     //create new record
  94.     var selHnd = this.getSelectionHandle();
  95.     selHnd.NewRecord();
  96.  
  97.     //generate a PK if necessary
  98.     var pkValue = -1
  99.       if ( this.pkName != null ){
  100.         pkValue = this.getNextSequence();
  101.         selHnd.SetField(this.pkName, pkValue);
  102.       }
  103.  
  104.       //set values for each field
  105.       for (var i=0; i < fields.length; i++){
  106.         NOF.Contract.Require( fields[i].name != this.pkName, "You cannot specifiy a value for autogenerated keys! " +this.pkName);
  107.         selHnd.SetField( fields[i].name, (fields[i].value != null) ? fields[i].value : "" );
  108.       }
  109.  
  110.       //update the record
  111.       selHnd.Update();
  112.  
  113.     return pkValue;
  114.   };
  115.  
  116.   /**
  117.     * create creates a FSITable and the associated FSISelection
  118.     * @param instanceId the table type
  119.  
  120.     * @return selHnd the associated FSISelection handle
  121.   */
  122.   method.create = function create( instanceId ){
  123.     NOF.Contract.Require( this.name != null && this.name.length > 0, "Name has to be defined!");
  124.  
  125.     var qualifiedTableName = this.getFullTableName( instanceId );
  126.     var selHnd = this._GetSelectionHandle( qualifiedTableName );
  127.     if ( selHnd == null ){
  128.       var fsiApp = NOF.App.getFSIApp();
  129.       //var table = fsiApp.NewTable( this.name,  this.type);
  130.       var table = fsiApp.NewTable( qualifiedTableName,  this.type);
  131.  
  132.       NOF.Contract.Assert( table != null, "Database inconsistency! Table already exists when it should not");
  133.       var fieldsList = this.getDDL();
  134.       for (var i=0; i < fieldsList.length; i++){
  135.         table.AddField( fieldsList[i].name, fieldsList[i].type );
  136.       }
  137.  
  138.       selHnd = fsiApp.NewSelection( qualifiedTableName, this.type );
  139.       selHnd.SetTable( table );
  140.     }
  141.  
  142.     return selHnd;
  143.   };
  144.  
  145.   /**
  146.     * getRecordsCount
  147.  
  148.     * @return the records count
  149.   */
  150.   method.getRecordsCount = function getRecordsCount(){
  151.     return this.getSelectionHandle().Count();
  152.   };
  153.  
  154.   method.getTableName = function getTableName(){
  155.     return this.name;
  156.   };
  157.  
  158.   /**
  159.     * getFullTableName
  160.     * @param [instanceId] the table instance number
  161.  
  162.     * @return the full name as name + type in case type is defined.
  163.   */
  164.   method.getFullTableName = function getFullTableName( instanceId ){
  165.     var typeStr = (instanceId != null ? instanceId : 0);
  166.     typeStr     = (typeStr!= null ?  "_" + typeStr : "");
  167.     return this.name + typeStr;
  168.   };
  169.  
  170.   /**
  171.     * getTable initialises the table by loading the associated FSISelection,<br>
  172.     * setting the sequence value if it has a primary key
  173.     * @param instanceId the table instance number
  174.  
  175.     * @return the Table instance associated w/ the requested <code>type</code>
  176.   */
  177.   method.getTable = function getTable( instanceId ){
  178.     //check in the cache. load it if not accessed yet.
  179.     var tableId = this.getFullTableName ( instanceId );
  180.     if ( NOF_DataObjects_Table_LoadedTables[tableId] == null ){
  181.       var selHnd = this._GetSelectionHandle( instanceId );
  182.       if ( selHnd == null )//table not created yet. go ahead and create it
  183.         selHnd  = this.create( instanceId );
  184.  
  185.       var table = new this.__constructor__();
  186.       table.setSelectionHandle( selHnd );
  187.       table.instanceId = instanceId;
  188.  
  189.       NOF_DataObjects_Table_LoadedTables[tableId] = table;
  190.  
  191.       if ( this.pkName != null ){//table has a primary key
  192.         if ( selHnd.Count() > 0){
  193.           selHnd.SetIndex( selHnd.Count() - 1 ); //move it to the last position. might be safer to compute the maximum instead of relying on ordered rows!
  194.           var curSeq = 0 + selHnd.GetField( this.pkName );
  195.           table._setSequence( curSeq++ );
  196.         }else{
  197.           table._setSequence( 0 );
  198.         }
  199.       }
  200.     }
  201.  
  202.     return  NOF_DataObjects_Table_LoadedTables[tableId];
  203.   };
  204.  
  205.   /**
  206.     * getDDL - abstract method. subclasses needs to provide the concrete DDL for the specific table they implement.
  207.     * <br>DDL is an array of FieldsInfo objects
  208.   */
  209.   method.getDDL = function getDDL(){
  210.     throw new NOF.UTIL.AbstractMethodError( "Table.getDDL is an abstract method!");
  211.   };
  212.  
  213.   //various class member accessors
  214.   method.getSelectionHandle = function getSelectionHandle(){return this.fisSelection;};
  215.   method.setSelectionHandle = function setSelectionHandle( hnd ){
  216.     this.fisSelection = hnd;
  217.   };
  218.  
  219.   method.getType   = function getType(){return this.type;};
  220.   method.getName   = function getName(){return this.name;};
  221.   method.getPkName = function getName(){return this.pkName;};
  222.  
  223.   /**
  224.     * selectAll fetches all table records
  225.     *
  226.     * @return resultSet an array of arrays of FieldValue objects. it is NEVER null.
  227.   */
  228.   method.selectAll = function selectAll(){
  229.     return this.selectByFields();
  230.   };
  231.  
  232.   /**
  233.     * selectByFields
  234.     * @param fields an array of FieldValue object. can be empty and will match all the records
  235.     * @return resultSet an array of arrays of FieldValue objects. it is NEVER null.
  236.   */
  237.   method.selectByFields = function selectByFields( fields ){
  238.     var resultSet = new Array();
  239.     var tableDDL  = this.getDDL();
  240.     var selHnd    = this.getSelectionHandle();
  241.     var str = "";
  242.     if (fields == null)
  243.       str = "ALL";
  244.  
  245.     function _selectVisitor(){
  246.       var record = new Array();
  247.  
  248.       for (var i=0; i < tableDDL.length; i++)
  249.         record.add( new  NOF_DataObjects_FieldValue( tableDDL[i].name, "" + selHnd.GetField(tableDDL[i].name) ) );
  250.  
  251.       resultSet.add( record );
  252.     }
  253.  
  254.     this.VisitRowsByFields(fields, _selectVisitor);
  255.     return resultSet;
  256.   };
  257.  
  258.   /**
  259.     * selectByIndex reads the record at the specified index
  260.     * @param index a valid positive numeric value
  261.   */
  262.   method.selectByIndex = function selectByIndex( index ){
  263.     if ( this.moveTo( index ) ){
  264.       var selHnd    = this.getSelectionHandle();
  265.       var tableDDL  = this.getDDL();
  266.  
  267.       var record = new Array();
  268.       for (var i=0; i < tableDDL.length; i++)
  269.         record.add( new  NOF_DataObjects_FieldValue( tableDDL[i].name, "" + selHnd.GetField(tableDDL[i].name) ) );
  270.  
  271.       return record;
  272.     }else{
  273.       return null;
  274.     }
  275.   };
  276.  
  277.   /**
  278.     * VisitRowsByFields iterates over the records list and invokes the callback method w/ the field index<br>
  279.  
  280.     * @param fields an array of FieldValue objects. can be empty and will match all the record
  281.     * @param visitorCB  a function referenced that will be invoked everytime a match is found
  282.   */
  283.   method.VisitRowsByFields = function VisitRowsByField( fields, visitorCB ){
  284.     NOF.Contract.Require( visitorCB != null && typeof (visitorCB) == 'function', "Second argument needs to be a valid function pointer!");
  285.  
  286.     var recCount = this.getRecordsCount();
  287.     if (recCount > 0){
  288.       var selHnd    = this.getSelectionHandle();
  289.       selHnd.SetIndex(0); //make sure we start from the begining
  290.       var isSearchByPK = false;
  291.       if (fields != null) {
  292.         for (var i=0; i<fields.length;i++){//determine whether pk is a condition to stop after first match
  293.           if ( fields[i].name == this.pkName ){
  294.             isSearchByPK = true;
  295.             break;
  296.           }
  297.         }
  298.       }
  299.  
  300.       for ( var i=0; i < recCount; i++ ){
  301.         if ( fields == null){//call back uncoditionally
  302.           visitorCB( i );
  303.         }else{
  304.           var matches = true;
  305.           for (var j=0; j < fields.length; j++){
  306.             if ( selHnd.GetField( fields[j].name ) != fields[j].value ){
  307.               matches = false;
  308.               break;
  309.             }
  310.           }
  311.  
  312.           if ( matches ){
  313.             visitorCB( i );
  314.             if ( isSearchByPK ) //the search should end here if we're looking for the primaryKey
  315.               break;
  316.           }
  317.  
  318.         }
  319.         selHnd.NextRecord();
  320.       }
  321.     }
  322.   };
  323.  
  324.   /**
  325.     * updateByFields updates the matching field(s) w/ the new values
  326.     * @param fields an array of FieldValue objects.
  327.     * @param newRowValue a valid array of FieldValues objects
  328.  
  329.     * @return count the number of rows that were updated
  330.   */
  331.   method.updateByFields = function updateByFields(fields, newRowValue){
  332.     NOF.Contract.Require( fields != null, "Where clause (first argument ) cannot be empty!");
  333.     NOF.Contract.Require( newRowValue != null && newRowValue.length != null && newRowValue.length > 0, "Set clause (second arg) cannot be empty!");
  334.  
  335.     var count = 0;
  336.     var selHnd  = this.getSelectionHandle();
  337.  
  338.     function _updateVisitor(){
  339.       for (var i=0; i < newRowValue.length; i++)
  340.         selHnd.SetField( newRowValue[i].name, (newRowValue[i].value != null) ? newRowValue[i].value : "");
  341.  
  342.       selHnd.Update();
  343.       count++;
  344.     }
  345.  
  346.     this.VisitRowsByFields( fields, _updateVisitor);
  347.  
  348.     return count;
  349.   };
  350.  
  351.   /**
  352.     * updateByIndex updates the record referenced <code>index</code>
  353.     * @param index a valid positive numeric value
  354.     * @param newRowValue a valid array of FieldValues objects
  355.   */
  356.   method.updateByIndex = function updateByIndex( index, newRowValue ){
  357.     if ( this.moveTo( index ) ){
  358.       var selHnd    = this.getSelectionHandle();
  359.       for (var i=0; i < newRowValue.length; i++)
  360.         selHnd.SetField( newRowValue[i].name, (newRowValue[i].value != null) ? newRowValue[i].value : "");
  361.  
  362.       selHnd.Update();
  363.     }
  364.   };
  365.  
  366.   /**
  367.     * deleteAll literally deletes all the records of the table
  368.     * @param [resetSequence] determines wheather the seqenece is reset to 0 or not. default is true;
  369.     *
  370.   */
  371.   method.deleteAll = function deleteAll( resetSequence ){
  372.     resetSequence = (resetSequence != null ? resetSequence : true); //default behaviour is to reset it
  373.     var selHnd = this.getSelectionHandle();
  374.     if (this.getRecordsCount() > 0){
  375.       selHnd.SetIndex(0); //make sure we start from the begining
  376.       while ( this.getRecordsCount() )
  377.         selHnd.DeleteRecord();
  378.     }
  379.  
  380.     NOF.Contract.Ensure( selHnd.Count() == 0, "Record count should be 0 after a delete all!");
  381.     if ( resetSequence )
  382.       this._setSequence( 0 ); //reset the sequence if all rows were deleted
  383.   };
  384.  
  385.   /**
  386.     * deleteByFields deletes all the fields that matches given condition
  387.     * @param fields an array of FieldValue object.
  388.  
  389.     * @return count the number of rows that were deleted
  390.   */
  391.   method.deleteByFields = function deleteByFields( fields ){
  392.     NOF.Contract.Require( fields != null, "Where clause cannot be empty!");
  393.  
  394.     var count = 0;
  395.     var recCount = this.getRecordsCount();
  396.     var isPK = false;
  397.     for (var i=0; i<fields.length;i++) {
  398.       if (fields[i].name == this.pkName) {
  399.         isPK = true;
  400.         break;
  401.       }
  402.     }
  403.     if (recCount > 0){
  404.       var selHnd    = this.getSelectionHandle();
  405.       selHnd.SetIndex(0); //make sure we start from the begining
  406.       for ( var i=0; i < recCount; i++ ){
  407.         var matched = true;
  408.         for (var j=0; j<fields.length;j++) {
  409.           if ( selHnd.GetField( fields[j].name ) != fields[j].value ) {
  410.             matched = false;
  411.             break;
  412.           }
  413.         }
  414.         if ( matched ) {
  415.           selHnd.DeleteRecord();
  416.           selHnd.Update();
  417.           recCount--;
  418.           // do not skip record
  419.           i--;
  420.           count++;
  421.  
  422.           if ( isPK ) //the search should end here if we're looking for the primaryKey
  423.             break;
  424.         }else{
  425.           selHnd.NextRecord();
  426.         }
  427.       }
  428.     }
  429.  
  430.     return count;
  431.   };
  432.  
  433.   /**
  434.     * deleteByIndex deletes the record at the specified index
  435.     * @param index a valid positive numeric value
  436.   */
  437.   method.deleteByIndex = function deleteByIndex( index ){
  438.     if ( this.moveTo( index ) ){
  439.       var selHnd    = this.getSelectionHandle();
  440.       selHnd.DeleteRecord();
  441.       selHnd.Update();
  442.     }
  443.   };
  444.  
  445.   /**
  446.     * moveTo moves the record pointer to the specified index
  447.     * @param index a valid positive numeric value
  448.  
  449.     * @return count the number of rows that were deleted
  450.   */
  451.   method.moveTo = function moveTo( index ){
  452.     var re = /^[0-9]+$/;NOF.Contract.Require( re.test( index ), "Index has to be a digit value!");
  453.     var recCount = this.getRecordsCount();
  454.     NOF.Contract.Require( index >=0 && index < recCount, "Index out of range!");
  455.  
  456.     if (recCount > 0){
  457.       return this.getSelectionHandle().SetIndex( index );
  458.     }else{
  459.       return false;
  460.     }
  461.   };
  462.  
  463.   /**
  464.     * _GetSelectionHandle
  465.     * @param instanceId the table instance number
  466.  
  467.     * @return selHnd the FSISelection object associated with the given table
  468.   */
  469.   method._GetSelectionHandle = function _GetSelectionHandle( instanceId ){
  470.     return this._GetSelectionByName( this.getFullTableName( instanceId ) );
  471.   };
  472.  
  473.   /**
  474.     * _GetSelectionByName looks up the selections list by name
  475.     * @param name the FSISelection name
  476.  
  477.     * @return selHnd the FSISelection object associated with <code>name</name>
  478.   */
  479.   method._GetSelectionByName = function _GetSelectionByName( name ){
  480.     if ( NOF_DataObjects_Table_SelectionsList[ name ] == null ){
  481.       var fsiApp = NOF.App.getFSIApp();
  482.       var selections = fsiApp.GetAllSelectionsByName( name );
  483.  
  484.       var count = selections.Count();
  485.       NOF.Contract.Assert( count <=1, "Selection name has to be unique!");
  486.       if ( count == 1)
  487.         NOF_DataObjects_Table_SelectionsList[ name ] = selections.GetNext();
  488.     }
  489.  
  490.     return NOF_DataObjects_Table_SelectionsList[ name ];
  491.   };
  492.  
  493.   method.DEBUG = function DEBUG(caller, level){
  494.     var selHnd = this.getSelectionHandle();
  495.     //NOF.SysOut.info("[" + caller + "] " + "tName=" + this.name + " sName=" + selHnd.Name + " rowCount" + selHnd.Count());
  496.   }
  497.  
  498.   method.release = function release(){
  499.       this.fisSelection = null;
  500.   }
  501.  
  502.   method.clearCache = function clearCache(){
  503.     //debugger;
  504.     var arr = NOF_DataObjects_Table_LoadedTables;
  505.     for ( var item in arr)
  506.       if ( typeof( arr[item] ) != 'function' ){
  507.         //NOF.SysOut.info("releasing table: " + item);
  508.         arr[item].release();
  509.         arr[item] = null;
  510.       }
  511.  
  512.     arr  = null;
  513.     NOF_DataObjects_Table_LoadedTables = null;
  514.  
  515.     arr = NOF_DataObjects_Table_SelectionsList;
  516.     for ( var item in arr)
  517.       if ( typeof( arr[item] ) != 'function' )
  518.         arr[item] = null;
  519.  
  520.     arr =  null;
  521.     NOF_DataObjects_Table_SelectionsList = null;
  522.   }
  523.  
  524.   method.super_clearCache  = method.clearCache;
  525. }
  526.  
  527. NOF_DataObjects_Table_ProtoBuilder();
  528.  
  529. /**
  530.   * DataObjects namespace
  531. */
  532. function NOF_DataObjects(){
  533.   this.__proto__ = NOF_DataObjects.prototype;
  534.  
  535.   this.Table      = NOF_DataObjects_Table;
  536.   this.FieldInfo  = NOF_DataObjects_FieldInfo;
  537.   this.FieldValue = NOF_DataObjects_FieldValue;
  538.   this.FieldType  = new NOF_DataObjects_FieldType;
  539. }
  540.  
  541. NOF.__proto__.DO = new NOF_DataObjects();